using Microsoft.EntityFrameworkCore;
using CollabApp.Domain.Entities;
using CollabApp.Domain.Entities.Auth;
using CollabApp.Domain.Entities.Room;
using CollabApp.Domain.Entities.Game;

namespace CollabApp.Infrastructure.Data;

/// <summary>
/// 应用程序数据库上下文 - 主要的EF Core DbContext
/// 负责所有实体的配置和数据库操作
/// </summary>
public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
    {
    }

    // ============ 用户相关实体 ============
    
    /// <summary>
    /// 用户实体集合
    /// </summary>
    public DbSet<User> Users { get; set; }
    
    /// <summary>
    /// 用户统计实体集合
    /// </summary>
    public DbSet<UserStatistics> UserStatistics { get; set; }

    // ============ 房间相关实体 ============
    
    /// <summary>
    /// 房间实体集合
    /// </summary>
    public DbSet<Room> Rooms { get; set; }
    
    /// <summary>
    /// 房间玩家实体集合
    /// </summary>
    public DbSet<RoomPlayer> RoomPlayers { get; set; }
    
    /// <summary>
    /// 房间消息实体集合
    /// </summary>
    public DbSet<RoomMessage> RoomMessages { get; set; }

    // ============ 游戏相关实体 ============
    
    /// <summary>
    /// 游戏实体集合
    /// </summary>
    public DbSet<Game> Games { get; set; }
    
    /// <summary>
    /// 游戏玩家实体集合
    /// </summary>
    public DbSet<GamePlayer> GamePlayers { get; set; }
    
    /// <summary>
    /// 游戏操作实体集合
    /// </summary>
    public DbSet<GameAction> GameActions { get; set; }

    // ============ 排行榜和通知实体 ============
    
    /// <summary>
    /// 排行榜实体集合
    /// </summary>
    public DbSet<Ranking> Rankings { get; set; }
    
    /// <summary>
    /// 排名历史实体集合
    /// </summary>
    public DbSet<RankingHistory> RankingHistories { get; set; }
    
    /// <summary>
    /// 通知实体集合
    /// </summary>
    public DbSet<Notification> Notifications { get; set; }

    /// <summary>
    /// 配置实体模型和关系
    /// </summary>
    /// <param name="modelBuilder">模型构建器</param>
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        // ============ 用户相关配置 ============
        
        // 用户实体配置
        modelBuilder.Entity<User>(entity =>
        {
            // 索引配置
            entity.HasIndex(e => e.Username).IsUnique().HasDatabaseName("IX_Users_Username");
            entity.HasIndex(e => e.AccessToken).HasFilter("[access_token] IS NOT NULL").HasDatabaseName("IX_Users_AccessToken");
            entity.HasIndex(e => e.RefreshToken).HasFilter("[refresh_token] IS NOT NULL").HasDatabaseName("IX_Users_RefreshToken");
            entity.HasIndex(e => new { e.TokenStatus, e.AccessTokenExpiresAt }).HasDatabaseName("IX_Users_TokenStatus_AccessTokenExpires");
            entity.HasIndex(e => new { e.TokenStatus, e.RefreshTokenExpiresAt }).HasDatabaseName("IX_Users_TokenStatus_RefreshTokenExpires");
            entity.HasIndex(e => e.LastActivityAt).HasDatabaseName("IX_Users_LastActivity");
            entity.HasIndex(e => e.Status).HasDatabaseName("IX_Users_Status");
            
            // 软删除全局过滤器
            entity.HasQueryFilter(e => !e.IsDeleted);
        });

        // 用户统计实体配置
        modelBuilder.Entity<UserStatistics>(entity =>
        {
            // 一对一关系配置
            entity.HasOne(e => e.User)
                  .WithOne(e => e.Statistics)
                  .HasForeignKey<UserStatistics>(e => e.UserId)
                  .OnDelete(DeleteBehavior.Cascade);
                  
            // 索引配置
            entity.HasIndex(e => e.UserId).IsUnique().HasDatabaseName("IX_UserStatistics_UserId");
            entity.HasIndex(e => e.CurrentRank).HasDatabaseName("IX_UserStatistics_CurrentRank");
            entity.HasIndex(e => e.TotalScore).HasDatabaseName("IX_UserStatistics_TotalScore");
            entity.HasIndex(e => e.WinRate).HasDatabaseName("IX_UserStatistics_WinRate");
            
            // 软删除全局过滤器
            entity.HasQueryFilter(e => !e.IsDeleted);
        });

        // ============ 房间相关配置 ============
        
        // 房间实体配置
        modelBuilder.Entity<Room>(entity =>
        {
            // 外键关系配置
            entity.HasOne(e => e.Owner)
                  .WithMany(e => e.OwnedRooms)
                  .HasForeignKey(e => e.OwnerId)
                  .OnDelete(DeleteBehavior.Restrict);
                  
            // 索引配置
            entity.HasIndex(e => e.OwnerId).HasDatabaseName("IX_Rooms_OwnerId");
            entity.HasIndex(e => e.Status).HasDatabaseName("IX_Rooms_Status");
            entity.HasIndex(e => new { e.Status, e.IsPrivate }).HasDatabaseName("IX_Rooms_Status_IsPrivate");
            entity.HasIndex(e => e.CreatedAt).HasDatabaseName("IX_Rooms_CreatedAt");
            
            // 软删除全局过滤器
            entity.HasQueryFilter(e => !e.IsDeleted);
        });

        // 房间玩家实体配置
        modelBuilder.Entity<RoomPlayer>(entity =>
        {
            // 外键关系配置
            entity.HasOne(e => e.Room)
                  .WithMany(e => e.Players)
                  .HasForeignKey(e => e.RoomId)
                  .OnDelete(DeleteBehavior.Cascade);
                  
            entity.HasOne(e => e.User)
                  .WithMany(e => e.RoomPlayers)
                  .HasForeignKey(e => e.UserId)
                  .OnDelete(DeleteBehavior.Cascade);
                  
            // 复合唯一索引 - 确保同一用户在同一房间只能有一条记录（只对未删除的记录生效）
            entity.HasIndex(e => new { e.RoomId, e.UserId })
                  .IsUnique()
                  .HasDatabaseName("IX_RoomPlayers_RoomId_UserId")
                  .HasFilter("NOT is_deleted"); // 只对未删除的记录应用唯一约束
            entity.HasIndex(e => e.JoinOrder).HasDatabaseName("IX_RoomPlayers_JoinOrder");
        });

        // 房间消息实体配置
        modelBuilder.Entity<RoomMessage>(entity =>
        {
            // 外键关系配置
            entity.HasOne(e => e.Room)
                  .WithMany(e => e.Messages)
                  .HasForeignKey(e => e.RoomId)
                  .OnDelete(DeleteBehavior.Cascade);
                  
            entity.HasOne(e => e.User)
                  .WithMany()
                  .HasForeignKey(e => e.UserId)
                  .OnDelete(DeleteBehavior.Restrict);
                  
            // 索引配置
            entity.HasIndex(e => e.RoomId).HasDatabaseName("IX_RoomMessages_RoomId");
            entity.HasIndex(e => e.UserId).HasDatabaseName("IX_RoomMessages_UserId");
            entity.HasIndex(e => e.CreatedAt).HasDatabaseName("IX_RoomMessages_CreatedAt");
            entity.HasIndex(e => new { e.RoomId, e.CreatedAt }).HasDatabaseName("IX_RoomMessages_RoomId_CreatedAt");
        });

        // ============ 游戏相关配置 ============
        
        // 游戏实体配置
        modelBuilder.Entity<Game>(entity =>
        {
            // 外键关系配置
            entity.HasOne(e => e.Room)
                  .WithMany(e => e.Games)
                  .HasForeignKey(e => e.RoomId)
                  .OnDelete(DeleteBehavior.Cascade);
                  
            entity.HasOne(e => e.Winner)
                  .WithMany()
                  .HasForeignKey(e => e.WinnerId)
                  .OnDelete(DeleteBehavior.SetNull);
                  
            // 索引配置
            entity.HasIndex(e => e.RoomId).HasDatabaseName("IX_Games_RoomId");
            entity.HasIndex(e => e.Status).HasDatabaseName("IX_Games_Status");
            entity.HasIndex(e => e.WinnerId).HasDatabaseName("IX_Games_WinnerId");
            entity.HasIndex(e => e.StartedAt).HasDatabaseName("IX_Games_StartedAt");
            entity.HasIndex(e => e.FinishedAt).HasDatabaseName("IX_Games_FinishedAt");
            
            // 软删除全局过滤器
            entity.HasQueryFilter(e => !e.IsDeleted);
        });

        // 游戏玩家实体配置
        modelBuilder.Entity<GamePlayer>(entity =>
        {
            // 外键关系配置
            entity.HasOne(e => e.Game)
                  .WithMany(e => e.Players)
                  .HasForeignKey(e => e.GameId)
                  .OnDelete(DeleteBehavior.Cascade);
                  
            entity.HasOne(e => e.User)
                  .WithMany(e => e.GamePlayers)
                  .HasForeignKey(e => e.UserId)
                  .OnDelete(DeleteBehavior.Cascade);
                  
            // 复合唯一索引 - 确保同一用户在同一游戏只能有一条记录
            entity.HasIndex(e => new { e.GameId, e.UserId }).IsUnique().HasDatabaseName("IX_GamePlayers_GameId_UserId");
            entity.HasIndex(e => e.FinalRank).HasDatabaseName("IX_GamePlayers_FinalRank");
            entity.HasIndex(e => e.FinalArea).HasDatabaseName("IX_GamePlayers_FinalArea");
            entity.HasIndex(e => e.ScoreChange).HasDatabaseName("IX_GamePlayers_ScoreChange");
        });

        // 游戏操作实体配置
        modelBuilder.Entity<GameAction>(entity =>
        {
            // 外键关系配置
            entity.HasOne(e => e.Game)
                  .WithMany(e => e.Actions)
                  .HasForeignKey(e => e.GameId)
                  .OnDelete(DeleteBehavior.Cascade);
                  
            entity.HasOne(e => e.User)
                  .WithMany()
                  .HasForeignKey(e => e.UserId)
                  .OnDelete(DeleteBehavior.Restrict);
                  
            // 索引配置
            entity.HasIndex(e => e.GameId).HasDatabaseName("IX_GameActions_GameId");
            entity.HasIndex(e => e.UserId).HasDatabaseName("IX_GameActions_UserId");
            entity.HasIndex(e => e.Timestamp).HasDatabaseName("IX_GameActions_Timestamp");
            entity.HasIndex(e => new { e.GameId, e.Timestamp }).HasDatabaseName("IX_GameActions_GameId_Timestamp");
            entity.HasIndex(e => e.ActionType).HasDatabaseName("IX_GameActions_ActionType");
        });

        // ============ 排行榜和通知配置 ============
        
        // 排行榜实体配置
        modelBuilder.Entity<Ranking>(entity =>
        {
            // 外键关系配置
            entity.HasOne(e => e.User)
                  .WithMany()
                  .HasForeignKey(e => e.UserId)
                  .OnDelete(DeleteBehavior.Cascade);
                  
            // 复合唯一索引 - 确保同一用户在同一类型排行榜同一周期只能有一条记录
            entity.HasIndex(e => new { e.UserId, e.RankingType, e.PeriodStart, e.PeriodEnd })
                  .IsUnique()
                  .HasDatabaseName("IX_Rankings_UserId_Type_Period");
            entity.HasIndex(e => new { e.RankingType, e.CurrentRank }).HasDatabaseName("IX_Rankings_Type_Rank");
            entity.HasIndex(e => new { e.RankingType, e.Score }).HasDatabaseName("IX_Rankings_Type_Score");
            entity.HasIndex(e => e.UpdatedAt).HasDatabaseName("IX_Rankings_UpdatedAt");
        });

        // 排名历史实体配置
        modelBuilder.Entity<RankingHistory>(entity =>
        {
            // 外键关系配置
            entity.HasOne(e => e.User)
                  .WithMany()
                  .HasForeignKey(e => e.UserId)
                  .OnDelete(DeleteBehavior.Cascade);
                  
            // 索引配置
            entity.HasIndex(e => e.UserId).HasDatabaseName("IX_RankingHistories_UserId");
            entity.HasIndex(e => new { e.RankingType, e.RecordedAt }).HasDatabaseName("IX_RankingHistories_Type_RecordedAt");
            entity.HasIndex(e => new { e.UserId, e.RankingType, e.RecordedAt }).HasDatabaseName("IX_RankingHistories_UserId_Type_RecordedAt");
        });

        // 通知实体配置
        modelBuilder.Entity<Notification>(entity =>
        {
            // 外键关系配置
            entity.HasOne(e => e.User)
                  .WithMany(e => e.Notifications)
                  .HasForeignKey(e => e.UserId)
                  .OnDelete(DeleteBehavior.Cascade);
                  
            // 索引配置
            entity.HasIndex(e => e.UserId).HasDatabaseName("IX_Notifications_UserId");
            entity.HasIndex(e => new { e.UserId, e.IsRead }).HasDatabaseName("IX_Notifications_UserId_IsRead");
            entity.HasIndex(e => e.NotificationType).HasDatabaseName("IX_Notifications_Type");
            entity.HasIndex(e => e.CreatedAt).HasDatabaseName("IX_Notifications_CreatedAt");
            entity.HasIndex(e => new { e.UserId, e.CreatedAt }).HasDatabaseName("IX_Notifications_UserId_CreatedAt");
        });
    }

    /// <summary>
    /// 重写SaveChanges方法，自动处理审计字段和软删除
    /// </summary>
    public override int SaveChanges()
    {
        HandleAuditFields();
        return base.SaveChanges();
    }

    /// <summary>
    /// 重写SaveChangesAsync方法，自动处理审计字段和软删除
    /// </summary>
    public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
    {
        HandleAuditFields();
        return await base.SaveChangesAsync(cancellationToken);
    }

    /// <summary>
    /// 处理审计字段的自动填充
    /// </summary>
    private void HandleAuditFields()
    {
        var entries = ChangeTracker.Entries()
            .Where(e => e.Entity is BaseEntity && 
                       (e.State == EntityState.Added || e.State == EntityState.Modified));

        foreach (var entry in entries)
        {
            var entity = (BaseEntity)entry.Entity;
            var now = DateTime.UtcNow;

            if (entry.State == EntityState.Added)
            {
                entity.CreatedAt = now;
            }

            entity.UpdatedAt = now;
        }
    }
}
